package geographer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

/**
 * Project #3
 * CS 2334, 010
 * 03/26/2014
 * <P>
 * This class creates a world map with a given set of points for a GUI.
 * </P>
 * @version 1.0
 */
public class WorldMap extends JPanel 
{
	/*The unique serial id for this world map*/
	private static final long serialVersionUID = 1L;
	
	/*The url for the map image*/
	private static java.net.URL url;
	
	/*The image to hold the world map*/
	private static BufferedImage img;
	
	/*Varios GUI constants for drawing*/
	private static final int POINT_RADIUS = 2;
	private static final int PADDING =3;
	private static final int SLANT = 3;
	private static final Color POINT_COLOR = Color.getHSBColor(0f,   1f,   1f);
	private static final Color LABEL_COLOR = Color.getHSBColor(0f, 0.8f, 0.55f);
	private static final Color FONT_COLOR  = Color.getHSBColor(0f, 0.2f, 0.95f);
	
	
	private  List<String> cityNames;
	private  List<Integer[]> points;
	
	//Retrieve the map image.
	static{
		try{
			/*
			 * This file is licensed under the Creative Commons 
			 * Attribution-Share Alike 3.0 Unported license.
			 */
			url = new java.net.URL("http://upload.wikimedia.org/wikipedia/commons/"+
								   "thumb/8/83/Equirectangular_projection_SW.jpg/"+
								   "1280px-Equirectangular_projection_SW.jpg");
			img = ImageIO.read(url);
			
		} catch (java.net.MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {					 
			e.printStackTrace();
		}
	}
	
	/**
	 * The constructor for a World Map.
	 */
	public WorldMap()
	{
		points = new ArrayList<Integer[]>();
		cityNames = new ArrayList<String>();
	}
	
	/**
	 * Add a point to the map.
	 * <P>
	 * Algorithm: <br>
	 * 1. Parse the data from a City object<br>
	 * 2. Add the name of the city<br>
	 * 3. Add the point to the map<br>
	 * </P>
	 * @param cityName   The name of the city
	 * @param la         The latitude of the city
	 * @param lo         The longitude of the city
	 * @return           Boolean value whether the point was added.
	 */
	public boolean addPoint(String cityName, String la, String lo)
	{
		//Parse data values
		Double longitude = (lo.charAt(0) == 'W' ? 1 : -1) * Double.valueOf(lo.substring(1)),
			   latitude  = (la.charAt(0) == 'N' ? 1 : -1) * Double.valueOf(la.substring(1));
		
		//Add the city name
		cityNames.add(cityName);
		
		//Return
		return points.add(new Integer[]{(int)((180-longitude)/180*img.getWidth()/2),
								 		(int)((90-latitude)/90*img.getHeight()/2)});
	}
	
	/**
	 * Paint the component onto the frame.
	 * <P>
	 * Algorithm: <br>
	 * 1. Set dimensions and initialize the graphics<br>
	 * 2. Draw the various components of the world map<br>
	 * @param g    The graphics component
	 */
	public void paintComponent(Graphics g)
	{
		super.paintComponent(g);
		
		//Initialize graphics.
		Graphics2D ig = img.createGraphics();
		ig.setRenderingHint(
			 RenderingHints.KEY_ANTIALIASING,
			 RenderingHints.VALUE_ANTIALIAS_ON);
		
		//Pixel dimensions of labels.
		Font f = new Font("Helvetica", Font.BOLD, 10);
		AffineTransform aft = new AffineTransform();
		FontRenderContext frc = new FontRenderContext(aft, true, true);
		Rectangle2D label;
		
		//Set the font.
		ig.setFont(f);
				
		//Draw the points on the map.
		for(int i=0; i<points.size(); ++i)
		{	
			//Get label dimensions.
			label = f.getStringBounds(cityNames.get(i), frc);
			
			//Draw label.
			ig.setColor(LABEL_COLOR);
			ig.fillPolygon(	new int[]{points.get(i)[0]+POINT_RADIUS+1, 
							   (int) (points.get(i)[0]+POINT_RADIUS+3*PADDING+SLANT+label.getWidth()+1),
							   (int) (points.get(i)[0]+POINT_RADIUS+3*PADDING+SLANT+label.getWidth()+1),
									  points.get(i)[0]+POINT_RADIUS+3*PADDING   
							}, 
							new int[]{points.get(i)[1],
									  points.get(i)[1],
									  points.get(i)[1]-(int)label.getHeight()-1,
									  points.get(i)[1]-(int)label.getHeight()-1
							}, 
			4);
			
			//Draw city name.
			ig.setColor(FONT_COLOR);
			ig.drawString(cityNames.get(i), points.get(i)[0]+POINT_RADIUS+2*PADDING+SLANT+1, points.get(i)[1]-3);
			
			//Draw point.
			ig.setColor(POINT_COLOR);
			ig.fillOval(points.get(i)[0]-POINT_RADIUS, points.get(i)[1]-POINT_RADIUS, 2*POINT_RADIUS, 2*POINT_RADIUS);
		}
		
		//Draw the map.
		g.drawImage(img,0,0,null);
	}
}

